package com.example.administrator.my2048game;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;
import java.util.ArrayList;
import java.util.List;

/**
 * 游戏界面类
 */
public class GameView extends GridLayout {
	public int cardWith = 4; // 卡片宽度
	// 定义一个二维数组来记录 GameView 初始化时生成的 cardWith * cardWith 个卡片
	private Card[][] cardsMap = new Card[cardWith][cardWith];
	private static GameView gameView = null;
    // 定义一个 List 来存放空的小方块
	private List<Point> points = new ArrayList<>();

	public static GameView getGameView() {
		return gameView;
	}

	public GameView(Context context) {
		super(context);
		gameView = this;
		initGameView();
	}

	public GameView(Context context, AttributeSet attrs) {
		super(context, attrs);
		gameView = this;
		initGameView();
	}

	public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		gameView = this;
		initGameView();
	}

	/**
	 * 初始化游戏界面
	 */
	public void initGameView() {
		setColumnCount(cardWith); // 指明是 cardWith 列的格子，否则初始只有一行
		setBackgroundColor(0xffbbada0);
		addCards(getScreenWidth(), getScreenWidth()); // 添加卡片
		startGame();
		setOnTouchListener(new OnTouchListener() {
			private float startX, startY; // 初始的位置
			private float offsetX, offsetY; // 偏移的值
			@Override
			public boolean onTouch(View view, MotionEvent event) {
				switch (event.getAction()) {
					case MotionEvent.ACTION_DOWN:
						startX  = event.getX();
						startY = event.getY();
						break;
					case MotionEvent.ACTION_UP:
						offsetX = event.getX() - startX;
						offsetY = event.getY() - startY;
                        // 在水平方向上移动
                        if (Math.abs(offsetX) > Math.abs(offsetY)) {  // 防止斜着滑动
							if (offsetX < -5) { // 向左滑动
                                swipeLeft();
							} else if (offsetX > 5) { // 向右滑动
                                swipeRight();
							}
						} else { // 在垂直方向上移动
							if (offsetY < -5) { // 向上滑动
								swipeUp();
							} else if (offsetY > 5) { //向下滑动
                                swipeDown();
							}
						}
						break;
				}
				return true;
			}
		});
	}

	/**
	 * 将小方块添加到布局中
	 */
	private void addCards(int cardWidth, int cardHeight) {
		Card c;
		for (int y = 0; y < cardWith; y++) {
			for (int x = 0; x < cardWith; x++) {
				c = new Card(getContext());
				c.setNum(0);
				addView(c, cardWidth, cardHeight);
				cardsMap[x][y] = c;
			}
		}
	}

	/**
	 * 获取屏幕的宽度
	 */
	private int getScreenWidth() {
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
		return (displayMetrics.widthPixels - 10) / cardWith; // 减去 10 是为了在屏幕左右留空隙
	}

	/**
	 * 开始游戏
	 */
	public void startGame() {
		for (int y = 0; y < cardWith; y++) {
			for (int x = 0; x < cardWith; x++) {
				cardsMap[x][y].setNum(0);
			}
		}
		// 开始生成两个随机数
		addRandomNum();
		addRandomNum();
	}

	// 设置随机数的方法。新生成的数字在这些空的小方块中随机出现
	private void addRandomNum() {
		// 把这个 point 清空，每次调用添加随机数时就清空之前的 List
		points.clear();
		// 对所有的位置进行遍历，即：将所有空格子搜集起来
		for (int y = 0; y < cardWith; y++) {
			for (int x = 0; x < cardWith; x++) {
				if (cardsMap[x][y].getNum() <= 0) {
					points.add(new Point(x, y)); // 添加所有空卡片
				}
			}
		}
		Point p = points.remove((int)(Math.random() * points.size())); // 从空卡片中随机一个卡片
		// 通过 point 对象来充当下标的角色来控制存放 card 的二维数组 cardsMap，然后随机给定位到的 card 对象赋值
		cardsMap[p.x][p.y].setNum(Math.random() > 0.1 ? 2 : 4); // 将生成 2 和 4 的概率指定为 9 : 1
	}

	// 向左滑
	private void swipeLeft() {
		boolean merge = false; // 是否合并的标志，初始不能合并
		for (int y = 0; y < cardWith; y++) {
			for (int x = 0; x < cardWith; x++) {
				for (int x1 = x + 1; x1 < cardWith; x1++) {
					// 这是在水平上固定了一个格子之后再继续在水平上遍历别的格子，且当格子有数的时候进行操作
					if (cardsMap[x1][y].getNum() > 0) {
						// 如果被固定的格子有没有数字
						if (cardsMap[x][y].getNum() <= 0) {
							// 把与被固定的格子的同一水平上的格子的数字赋给被固定的格子
							cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
							// 把值赋给被固定的格子后自己归零
							cardsMap[x1][y].setNum(0);
							// 同一行的不同列退一格继续循环，这样做的原因是为了继续固定这个格子而去检查与它同一水平上的别的格子的内容
							x--; // 和空卡片合并，还需要从当前位置计算（否则：|0|2|2|4| 左移之后变为 |2|2|4|0|，而正确的结果是 |4|4|0|0|）
							merge = true; //只要有移动就要加随机数
						} else if (cardsMap[x][y].equals(cardsMap[x1][y])) { // 这是判断相邻两个卡片数值相同的情况
							cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2); // 相同数字合并
							cardsMap[x1][y].setNum(0);
							MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); // 加分
							merge = true; //只要有移动就要加随机数
						}
						break;
					}
				}
			}
		}
		// 合并完成后添加一个随机数字并检查游戏是否结束
		if (merge) {
			addRandomNum();
			isGameOver();
		}
	}

	// 向右滑
	private void swipeRight() {
		boolean merge = false;
		for (int y = 0; y < cardWith; y++) {
			for (int x = cardWith - 1; x >= 0; x--) {
				for (int x1 = x - 1; x1 >= 0; x1--) {
					if (cardsMap[x1][y].getNum() > 0) {
						if (cardsMap[x][y].getNum() <= 0) {
							cardsMap[x][y].setNum(cardsMap[x1][y].getNum());
							cardsMap[x1][y].setNum(0);
							x++;
							merge = true;
						}else if (cardsMap[x][y].equals(cardsMap[x1][y])) {
							cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
							cardsMap[x1][y].setNum(0);
							MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
							merge = true;
						}
						break;

					}
				}
			}
		}
		if (merge) {
			addRandomNum();
			isGameOver();
		}
	}

	// 向上滑
	private void swipeUp() {
		boolean merge = false;
		for (int x = 0; x < cardWith; x++) {
			for (int y = 0; y < cardWith; y++) {
				for (int y1 = y + 1; y1 < cardWith; y1++) {
					if (cardsMap[x][y1].getNum() > 0) {
						if (cardsMap[x][y].getNum() <= 0) {
							cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
							cardsMap[x][y1].setNum(0);
							y--;
							merge = true;
						}else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
							cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
							cardsMap[x][y1].setNum(0);
							MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
							merge = true;
						}
						break;
					}
				}
			}
		}
		if (merge) {
			addRandomNum();
			isGameOver();
		}
	}

	// 向下滑
	private void swipeDown() {
		boolean merge = false;
		for (int x = 0; x < cardWith; x++) {
			for (int y = cardWith - 1; y >= 0; y--) {
				for (int y1 = y - 1; y1 >= 0; y1--) {
					if (cardsMap[x][y1].getNum() > 0) {
						if (cardsMap[x][y].getNum() <= 0) {
							cardsMap[x][y].setNum(cardsMap[x][y1].getNum());
							cardsMap[x][y1].setNum(0);
							y++;
							merge = true;
						} else if (cardsMap[x][y].equals(cardsMap[x][y1])) {
							cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);
							cardsMap[x][y1].setNum(0);
							MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());
							merge = true;
						}
						break;
					}
				}
			}
		}
		if (merge) {
			addRandomNum();
			isGameOver();
		}
	}

	/**
	 * 判断游戏是否结束。结束的标志：1.界面格子全满了；2.各个方向相邻的格子没有相同(可合并)的数字
	 */
	private void isGameOver() {
		boolean complete = true;
		ALL:
		for (int y = 0;y < cardWith; y++) {
			for (int x = 0; x < cardWith; x++) {
				if (cardsMap[x][y].getNum() == 0 || (x > 0 && cardsMap[x][y].equals(cardsMap[x - 1][y])) ||
					(x < cardWith - 1 && cardsMap[x][y].equals(cardsMap[x + 1][y])) ||
					(y > 0 && cardsMap[x][y].equals(cardsMap[x][y - 1])) ||
					(y < cardWith - 1 && cardsMap[x][y].equals(cardsMap[x][y + 1]))) {
					complete = false;
					break ALL;
				}
			}
		}
		if (complete) {
			AlertDialog.Builder alertDialog = new AlertDialog.Builder(getContext());
			alertDialog.setTitle("My2048").setMessage("对不起，游戏结束了！").setIcon(R.drawable.my2048game).setCancelable(false);
			alertDialog.setPositiveButton("重来一次", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					MainActivity.getMainActivity().clearScore();
					startGame();
					dialog.dismiss();
				}
			});
			alertDialog.setNegativeButton("确定", new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
				    dialog.dismiss();
                }
			});
			alertDialog.show();
		}
	}
}